package com.atguigu.lease.common.utils;

import com.atguigu.lease.common.exception.StgyException;
import com.atguigu.lease.common.result.ResultCodeEnum;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;

import javax.crypto.SecretKey;
import java.util.Date;

/**
 * @Author GQS @Date 2024/9/3/21:05 @Description
 */
public class JwtUtil {

    private static long tokenExpiration = 60 * 60 * 500 * 1000L; // 令牌过期时间，单位为毫秒，这里设置为500小时
    private static SecretKey tokenSignKey = Keys.hmacShaKeyFor("M0PKKI6pYGVWWfDZw90a0lTpGYX1d4AQ".getBytes()); // 签名密钥

    public static String createToken(Long userId, String username) {
        String token = Jwts.builder().
                setSubject("USER_INFO"). // 设置主题
                setExpiration(new Date(System.currentTimeMillis() + tokenExpiration)). // 设置过期时间
                claim("userId", userId). // 将userId加入声明
                claim("username", username).
                signWith(tokenSignKey). // 使用预定义的签名
                compressWith(CompressionCodecs.GZIP). // 压缩
                compact(); // 紧凑
        return token;
    }

    /**
     * 解析JWT令牌
     * 此方法用于验证和解析给定的JWT令牌字符串，从中提取出存储的声明
     * 它使用签名密钥来验证令牌的完整性，并检查其有效性（包括是否过期）
     *
     * @param token 要解析的JWT令牌字符串
     * @return Claims对象，包含解析后的令牌中的所有声明
     * @throws StgyException 如果令牌过期或无效，则抛出自定义异常StgyException，
     *                       分别对应于令牌过期和令牌无效的情况
     */
    public static Claims parseToken(String token) {
        try {
            // 使用指定的签名密钥解析JWT令牌
            Jws<Claims> claimsJws = Jwts.parserBuilder().
                    setSigningKey(tokenSignKey).
                    build().parseClaimsJws(token);
            // 返回解析出的声明部分
            return claimsJws.getBody();

        } catch (ExpiredJwtException e) {
            // 如果捕获到令牌过期异常，则抛出自定义异常，指示令牌已过期
            throw new StgyException(ResultCodeEnum.TOKEN_EXPIRED);
        } catch (JwtException e) {
            // 如果捕获到其他JWT异常，则抛出自定义异常，指示令牌无效
            throw new StgyException(ResultCodeEnum.TOKEN_INVALID);
        }
    }
}
